package com.ihr360.expr.core;

import com.ihr360.expr.ExprException;
import com.ihr360.expr.ExprExpression;
import com.ihr360.expr.context.IEvaluationContext;

import java.util.ArrayList;
import java.util.List;

public class ExprVariable extends ExprEvaluatable {
    private String name;
    private Object annotation;
    private Expr constantValue;

    public ExprVariable(String name) {
        super(ExprType.Variable);
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Object getAnnotation() {
        return annotation;
    }

    public void setAnnotation(Object annotation) {
        this.annotation = annotation;
    }

    public Expr getConstantValue() {
        return constantValue;
    }

    public void setConstantValue(Expr constantValue) {
        this.constantValue = constantValue;
    }

    @Override
    public Expr evaluate(IEvaluationContext context) throws ExprException {
        if (constantValue != null) {
            return constantValue;
        } else {
            return context.evaluateVariable(this);
        }
    }

    @Override
    public String toString() {
        return name;
    }

    @Override
    public int hashCode() {
        return name.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof ExprVariable)) {
            return false;
        }

        ExprVariable ev = (ExprVariable) obj;
        return ev.name.equals(name);
    }

    @Override
    public void validate() throws ExprException {
        if (name == null) {
            throw new ExprException("Variable name is empty");
        }
    }

    /**
     * 查找一个表达式中的所有变量
     *
     * @param expr
     * @return
     */
    public static ExprVariable[] findVariables(Expr expr) {
        List<ExprVariable> vars = new ArrayList();
        findVariables(expr, vars);
        return vars.toArray(new ExprVariable[0]);
    }

    public static void findVariables(Expr expr, List<ExprVariable> vars) {
        if (expr instanceof ExprVariable) {
            //是变量
            vars.add((ExprVariable) expr);
        } else if (expr instanceof IBinaryOperator) {
            //二元操作
            IBinaryOperator bo = (IBinaryOperator) expr;
            findVariables(bo.getLHS(), vars);
            findVariables(bo.getRHS(), vars);
        } else if (expr instanceof ExprExpression) {
            findVariables(((ExprExpression) expr).getChild());
        } else if (expr instanceof ExprFunction) {
            ExprFunction function = (ExprFunction) expr;
            for (Expr arg : function.getArgs()) {
                findVariables(arg, vars);
            }
        }
    }

}